﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Reflection;
using System.Text.RegularExpressions;
using System.Diagnostics;
using System.IO;
using System.Runtime.CompilerServices;

namespace ChEngine
{
    /// <summary>
    /// Chessboard based on Bruce Moreland 0x88 schema
    /// the piece array is 128 squares and addressing is
    /// index = rank*16+file
    /// </summary>
    public sealed class ChessBoard
    {
        /// <summary>
        /// Create a new bitboard with the start position...
        /// </summary>
        public ChessBoard()
            :this("rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1")
        {
            
        }
        static ChessBoard()
        {
            InitAttacksArray();
        }

       
        private int statusStackPointer;
        private static int[] whitePawnsMoves = new int[] { 16, 32, 15, 17 };
        private static int[] blackPawnMoves = new int[] { -16, -32, -15, -17 };
        private static int[] knightMoves = new int[] { -33, -31, -18, -14, 14, 18, 31, 33 };
        private static int[] kingMoves = new int[] { -17, -16, -15, -1, 1, 17, 16, 15 };
        private static int[] diagMoves = new int[] { -15, -17, 17, 15 };
        private static int[] straightMoves = new int[] { -16, -1, 16, 1 };

        private  static bool[] straightAttacks = new bool[240];
        private  static bool[] diagAttacks = new bool[240];
       
       
        private  static void InitAttacksArray()
        {
            
            for (int i = 0; i < 240; ++i)
            {
                int ox88Diff = i - 0x77;
                foreach (int a in diagMoves)
                {
                    if (ox88Diff % a == 0)
                    {
                        diagAttacks[i] = true;
                        break;
                    }
                }
                foreach (int a in straightMoves)
                {
                    if (ox88Diff % a == 0)
                    {
                        straightAttacks[i] = true;
                        break;
                    }
                }
            }
        }

#if BITMASK
        private ulong blackMask;
        private ulong whiteMask;

        /// <summary>
        /// Get the little endian bitmask of white pieces 
        /// </summary>
        public ulong WhitePieces
        {
            get
            {
                return whiteMask;
            }
        }
        /// <summary>
        /// Get the little endian bitmask of black pieces 
        /// </summary>
        public ulong BlackPieces
        {
            get
            {
                return blackMask;
            }
        }
#endif
        /// <summary>
        /// Get the pseudo legal moves for the current position. Pseudo legal
        /// means that there is no check for leaving the King in attack, and  
        /// generated castling does not check for having the king walking squares
        /// not under attack. This is for time optimization. In normal engine most of the moves
        /// are discarded, so the check for complete correctness is delayed when the move really need to
        /// executed.
        /// </summary>

        /// <param name="startIndex">The index to begin store the moves in the array</param>
        /// <param name="moves">A big enougth array to collect the moves</param>
        /// <returns>The count of generated moves</returns>
        public int GeneratePseudoLegalMoves(int startIndex, int[] moves)
        {
            int pListPointer,dest,move=0,ptr,d,i,firstEnemy,lastEnemy,firstSlider,lastSlider,moving,begin=startIndex;
            int[] pawnMoves;
            #region INITIALIZATION
            if ( toMove == Side.White )
            {
                firstEnemy = 16;
                lastEnemy = 32;
                pawnMoves = whitePawnsMoves;
                pListPointer = 0;
                firstSlider = firstSliderWhite;
                lastSlider = lastSliderBlack;
            }
            else
            {
                firstEnemy = 0;
                lastEnemy = 16;
                pawnMoves = blackPawnMoves;
                pListPointer = 16;
                firstSlider = firstSliderBlack;
                lastSlider = lastSliderBlack;
            }
           
            #endregion
            #region PAWNS
            // Pawns
            for (ptr = pListPointer + 1; ptr < pListPointer + 8; ++ptr)
            {
                i = pieceList[ptr] & 0xFF;
                if (0 != (i & 0x88))
                    continue;
                dest = i + pawnMoves[0];
                d = board[dest];
                if ((dest & 0x88) == 0 && d == NoPiece)
                {
                    if (dest < 112 && dest > 7) // no promotion
                    {
                        move = i;
                        move |= (dest << 8);
                        moves[startIndex++] = move;
                        dest = i + pawnMoves[1];
                        if (board[dest] == NoPiece)
                        {
                            if (toMove == Side.White && ((i >> 4) == 1))
                            {
                                move = i;
                                move |= (dest << 8);
                                moves[startIndex++] = move;
                            }
                            if (toMove == Side.Black && ((i >> 4) == 6))
                            {
                                move = i;
                                move |= (dest << 8);
                                moves[startIndex++] = move;
                            }
                        }
                    }
                    else
                    {
                        move = i;
                        move |= (dest << 8);
                        moves[startIndex++] = move | Queen << 16;
                        moves[startIndex++] = move | Knight << 16;
                        moves[startIndex++] = move | Bishop << 16;
                        moves[startIndex++] = move | Rook << 16; 
                    }
                }
                for (int j = 2; j <= 3; ++j)
                {
                    dest = i + pawnMoves[j];
                    d = board[dest];
                    if ((dest & 0x88) == 0
                        && ( (d>=firstEnemy && d<=lastEnemy) || dest == enPassantSquare))
                    {
                        if (dest < 112 && dest > 7) // no promotion
                        {
                            move = i;
                            move |= (dest << 8);
                            moves[startIndex++] = move;
                        }
                        else
                        {
                            move = i;
                            move |= (dest << 8);
                            moves[startIndex++] = move | Queen << 16;
                            moves[startIndex++] = move | Knight << 16;
                            moves[startIndex++] = move | Bishop << 16;
                            moves[startIndex++] = move | Rook << 16; ;
                        }
                    }
                }
            }
            #endregion
            #region KNIGHTS
            for ( ptr = pListPointer + 8; ptr<pListPointer+16 ; ++ptr)
            {
                if (ptr >= firstSlider)
                    break;
                i = pieceList[ptr] & 0xFF;
                if (0 != (i & 0x88))
                    continue;
                for (int j = 0; j < 8; ++j)
                {
                    dest = knightMoves[j] + i;
                    if (0 == (dest & 0x88))
                    {
                        d = board[dest];
                        if ( d == NoPiece || (d >= firstEnemy && d <= lastEnemy))
                        {
                            move = i;
                            move |= (dest << 8);
                            moves[startIndex++] = move;
                        }
                    }
                }
            }
            #endregion
            #region SLIDERS
            for (ptr = firstSlider; ptr <= lastSlider; ++ptr)
            {
                i = pieceList[ptr] & 0xFF;
                if (0 != (i & 0x88))
                    continue;
                moving = (pieceList[ptr] >> 8);
                #region DIAG
                if ((moving & DiagSliding) != 0)
                {
                    for (int j = 0; j < 4; ++j)
                    {
                        dest = i+diagMoves[j];
                        while ((dest & 0x88) == 0
                            )
                        {
                            d = board[dest];
                            if (!(d == NoPiece || (d >= firstEnemy && d <= lastEnemy)))
                                break;
                            move = i;
                            move |= (dest << 8);
                            if ( (d >= firstEnemy && d <= lastEnemy))
                            {
                                moves[startIndex++] = move;
                                break;
                            }
                            moves[startIndex++] = move;
                            dest += diagMoves[j];
                           
                        }
                    }
                }
                #endregion
                #region STRAIGHT
                if ((moving & StraightSliding) != 0)
                {
                    for (int j = 0; j < 4; ++j)
                    {
                        dest = i + straightMoves[j];
                        while ((dest & 0x88) == 0 
                            
                            )
                        {
                            d = board[dest];
                            if (!(d == NoPiece || (d >= firstEnemy && d <= lastEnemy)))
                                break;
                            move = i;
                            move |= (dest << 8);
                            if (d >= firstEnemy && d <= lastEnemy)
                            {
                                moves[startIndex++] = move;
                                break;
                            }
                            moves[startIndex++] = move;
                            dest += straightMoves[j];
                        }
                    }
                }
                #endregion
            }
            #endregion
            #region KING
            i = pieceList[pListPointer] & 0xFF;
            if (0 == (i & 0x88))
            {
                for (int j = 0; j < 8; ++j)
                {
                    dest = kingMoves[j] + i;
                    if (0 == (dest & 0x88) ) 
                        
                    {
                        d = board[dest];
                        if( !(d == NoPiece || (d >= firstEnemy && d <= lastEnemy)))
                            break;
                        move = i;
                        move |= (dest << 8);
                        moves[startIndex++] = move;
                    }
                }
                // castlings...
               
                if (i == (int) Cell.e1 && toMove == Side.White )
                {
                    if (0 != (castlingStatus & CastlingAvail.KingSideWhite)
                        && board[(int)Cell.f1] == NoPiece
                        && board[(int)Cell.g1] == NoPiece
                        )
                    {
                        move = i;
                        move |= ((int)Cell.g1 << 8);
                        moves[startIndex++] = move;
                    }
                    if (0 != (castlingStatus & CastlingAvail.QueenSideWhite)
                        && board[(int)Cell.d1] == NoPiece
                        && board[(int)Cell.c1] == NoPiece
                        && board[(int)Cell.b1] == NoPiece
                        )
                    {
                        move = i;
                        move |= ((int)Cell.c1 << 8);
                        moves[startIndex++] = move;
                    }
                }
                else if( i == (int) Cell.e8 && toMove == Side.Black )
                {
                    if (0 != (castlingStatus & CastlingAvail.KingSideBlack)
                        && board[(int)Cell.f8] == NoPiece
                        && board[(int)Cell.g8] == NoPiece
                        )
                    {
                        move = i;
                        move |= ((int)Cell.g8 << 8);
                        moves[startIndex++] = move;
                    }
                    if (0 != (castlingStatus & CastlingAvail.QueenSideBlack)
                        && board[(int)Cell.d8] == NoPiece
                        && board[(int)Cell.c8] == NoPiece
                        && board[(int)Cell.b8] == NoPiece
                        )
                    {
                        move = i;
                        move |= ((int)Cell.c8 << 8);
                        moves[startIndex++] = move;
                    }
                }
            }
            #endregion
            return startIndex - begin;
        }

        public ulong CurrentDivideNodeCount { get; set; }
        public string CurrentDivideMove { get; set; }
        /// <summary>
        /// This is the divide command. Used for checking move generator correctness
        /// Results of each divide are available subscribing the DividePartialResult event.
        /// </summary>
        /// <param name="depth">Depth to divide</param>
        /// <returns>The summary divide results</returns>
        public DivideResults Divide(int depth)
        {
            DivideResults div = new DivideResults();
            int[] moves = new int[200];
            div.MovesCount = GeneratePseudoLegalMoves( 0,moves);
            for (int i = 0; i < div.MovesCount; ++i)
            {
                if (IsMoveLegal(moves[i]))
                {
                    
                    Move(moves[i]);
                    if (InAttack(GetKingSquare(toMove == Side.White? Side.Black :Side.White),toMove) )
                    {
                        UndoMove(moves[i]);
                        continue;
                    }
                    
                    PerfResults pres = Perft(depth - 1);
                    div.NodesCount += pres.MovesCount;
                    CurrentDivideNodeCount = pres.MovesCount;
                    CurrentDivideMove = ToLiteralMove(moves[i]);
                    if (null != DividePartialResult)
                        DividePartialResult(this, EventArgs.Empty);
                    UndoMove(moves[i]);
                }
            }

            return div;
        }
        /// <summary>
        /// Signal a partial results during the "divide" execution.
        /// Used for debug / unit testing the move generator,or to use this generator
        /// as a ource for testing other generators.
        /// Detailed results about whats the "divide" partial results are can be found
        /// in the properties CurrentDivideNodeCount and CurrentDivideMove
        /// </summary>
        public event EventHandler DividePartialResult;

        /// <summary>
        /// Convert a packed move in its algebraic notation ( ex e2e4 ).
        /// No dexoration as + x # are appended to the string.
        /// </summary>
        /// <param name="move">The integer representing the move</param>
        /// <returns>The string representation of the move</returns>
        public string ToLiteralMove(int move)
        {
            string m = FromCellToLiteral((Cell)(move & 0xFF)) + FromCellToLiteral((Cell)((move >> 8) & 0xFF));
            int prom = (move >> 24) & 0xF;
            switch (prom)
            {
                case Queen:
                    m += "q";
                    break;
                case Rook:
                    m += "r";
                    break;
                case Bishop:
                    m += "b";
                    break;
                case Knight:
                    m += "n";
                    break;
            }
            return m;
        }
        /// <summary>
        /// Restore the board at the status before it moves. This is a low level routine and should not be used
        /// In user interaction.
        /// </summary>
        /// <param name="move">the move to undo</param>
        public void UndoMove(int move)
        {
            int dest = move & 0xFF;
            int start = (move >> 8) & 0xFF;
            if (toMove == Side.Black)
                toMove = Side.White;
            else
                toMove = Side.Black;
            int sindex = board[start];
            int eindex = board[dest];
            int moving = pieceList[sindex]>>8 & 0xFF;
            board[start] = NoPiece;
            
            PopStatus();
            int promotion = (capturePromotionStatus >> 16) & 0xFF;
            int captured = capturePromotionStatus >>4 & 0xF;
            if (promotion == 0 )
            {
                board[dest] = eindex;
                pieceList[eindex] = pieceList[sindex];
            }
            else
            {
                #region KNIGHTPROMOTION
                if (promotion == Knight)
                {
                    if (toMove == Side.White)
                    {
                        //shift the piece list one step back
                        // update board accordingly...
                        for (int i = firstSliderWhite; i < lastSliderWhite; ++i)
                        {
                            board[i] -= 1;
                        }
                        // shift piece list
                        Array.Copy(pieceList, firstSliderWhite, pieceList, firstSliderWhite - 1, lastSliderWhite - firstSliderWhite);
                        //Update pointers
                        firstSliderWhite--;
                        lastSliderWhite--;
                    }
                    else
                    {
                        //shift the piece list one step back
                        // update board accordingly...
                        for (int i = firstSliderBlack; i < lastSliderBlack; ++i)
                        {
                            board[i] -= 1;
                        }
                        // shift piece list
                        Array.Copy(pieceList, firstSliderBlack, pieceList, firstSliderBlack - 1, lastSliderBlack - firstSliderBlack);
                        //Update pointers
                        firstSliderBlack--;
                        lastSliderBlack--;
                    }
                }
                else
                #endregion
                #region PROMOTETOSLIDER
                {
                    if (toMove == Side.White)
                    {
                        lastSliderWhite--;
                    }
                    else
                    {
                        lastSliderBlack--;
                    }
                }
                #endregion
                if (toMove == Side.White)
                {
                    whiteMaterialValue += PawnValue;
                    whiteMaterialValue -= PieceValue(promotion);
                    // looks for the first pawn cell 
                    for (int i = 1; i < 9; ++i)
                    {
                        if (pieceList[i] == 0x88)
                        {
                            pieceList[i] = (short)(dest | (Pawn << 8));
                            break;
                        }
                    }
                }
                else
                {
                    blackMaterialValue += PawnValue;
                    blackMaterialValue -= PieceValue(promotion);
                    // looks for the first pawn cell 
                    for (int i = 17; i < 25; ++i)
                    {
                        if (pieceList[i] == 0x88)
                        {
                            pieceList[i] = (short)(dest | (Pawn << 8));
                            break;
                        }
                    }
                }
            }
            pieceList[sindex] = 0x88;
            if (captured != 0)
            {
                int destIndex = capturePromotionStatus & 0xFF;
                pieceList[destIndex] = (short)((capturePromotionStatus >> 8) & 0xFF);
                board[dest] = destIndex;
            }
            // castling...
            if (moving == King)
            {
                if (start == (int)Cell.g1 && dest == (int)Cell.e1)
                {
                    pieceList[board[(int)Cell.f1]] = (Rook << 8 | (int)Cell.h1);
                    board[(int)Cell.h1] = board[(int)Cell.f1];
                    board[(int)Cell.f1] = NoPiece;
                }
                if (start == (int)Cell.c1 && dest == (int)Cell.e1)
                {
                    pieceList[board[(int)Cell.d1]] = (Rook << 8 | (int)Cell.a1);
                    board[(int)Cell.a1] = board[(int)Cell.d1];
                    board[(int)Cell.d1] = NoPiece;
                }
                if (start == (int)Cell.g8 && dest == (int)Cell.e8)
                {
                    pieceList[board[(int)Cell.f8]] = (Rook << 8 | (int)Cell.h8);
                    board[(int)Cell.h8] = board[(int)Cell.f8];
                    board[(int)Cell.f8] = NoPiece;
                }
                if (start == (int)Cell.c8 && dest == (int)Cell.e8)
                {
                    pieceList[board[(int)Cell.d8]] = (Rook << 8 | (int)Cell.a8);
                    board[(int)Cell.a8] = board[(int)Cell.d8];
                    board[(int)Cell.d8] = NoPiece;
                }
            }
        }
        
        const ulong f1h1 = 0xa0UL;
        const ulong a1d1 = 0x9UL;
        const ulong f8h8 = 0xA000000000000000UL;
        const ulong a8d8 = 0x0900000000000000UL;
        /// <summary>
        /// This is the lowest level routine to generate a move. No check about legality
        /// is done ( for performance reason ) so this function is not suitable for user interaction.
        /// </summary>
        /// <param name="move">The move in the packed int format</param>
        public void Move(int move)
        {
            int start = move & 0xFF;
            int dest = (move >> 8) & 0xFF;
            int promotion = (move >> 16) & 0xF;
            
            bool captureEnPassant = false;
            int sindex = board[start];
            int eindex = board[dest];
            
            int captured = 0;
            int moving = pieceList[sindex] >> 8;
            if (eindex != NoPiece)
            {
                captured = pieceList[eindex] >> 8;
                capturePromotionStatus = dest;
                capturePromotionStatus |= pieceList[eindex] << 8;

            }
            else
                capturePromotionStatus = 0;
            
            board[start] = NoPiece;
            if (promotion == 0)
            {
                board[dest] = sindex;
                pieceList[sindex] = (short)dest;
            }
            else
            {
                pieceList[sindex] = 0x88;
                #region KNIGHTPROMOTION
                if (promotion == Knight)
                {
                    if (toMove == Side.White)
                    {
                        //shift the piece list one step
                        // update board accordingly...
                        for (int i = firstSliderWhite; i < lastSliderWhite; ++i)
                        {
                            board[i] += 1;
                        }
                        board[dest] = firstSliderWhite;
                        // shift piece list
                        Array.Copy(pieceList, firstSliderWhite, pieceList, firstSliderWhite + 1, lastSliderWhite - firstSliderWhite);
                        // update PieceList Knight Position
                        pieceList[firstSliderWhite] = (short)(dest | (Knight << 8));
                        //Update pointers
                        firstSliderWhite++;
                        lastSliderWhite++;
                    }
                    else
                    {
                        //shift the piece list one step
                        // update board accordingly...
                        for (int i = firstSliderBlack; i < lastSliderBlack; ++i)
                        {
                            board[i] += 1;
                        }
                        board[dest] = firstSliderBlack;
                        // shift piece list
                        Array.Copy(pieceList, firstSliderBlack, pieceList, firstSliderBlack + 1, lastSliderBlack - firstSliderBlack);
                        // update PieceList Knight Position
                        pieceList[firstSliderBlack] = (short)(dest | (Knight << 8));
                        //Update pointers
                        firstSliderBlack++;
                        lastSliderBlack++;
                    }
                }
                else
                #endregion
                #region PROMOTETOSLIDER
                {
                    if (toMove == Side.White)
                    {
                        lastSliderWhite++;
                        pieceList[lastSliderWhite] = (short)(dest | promotion << 8);
                        board[dest] = lastSliderWhite;
                    }
                    else
                    {
                        lastSliderBlack++;
                        pieceList[lastSliderBlack] = (short)(dest|promotion<<8);
                        board[dest] = lastSliderBlack;
                    }
                }
                #endregion
                capturePromotionStatus |= promotion << 16;
                if (toMove == Side.White)
                {
                    whiteMaterialValue -= PawnValue;
                    whiteMaterialValue += PieceValue(promotion);
                }
                else
                {
                    blackMaterialValue -= PawnValue;
                    blackMaterialValue += PieceValue(promotion);
                }
            }
            PushStatus();
            if (captured != 0)
            {
                halfMoves = 0;
                if (toMove == Side.White)
                {
                    blackMaterialValue -= PieceValue(captured);
                }
                else
                {
                    whiteMaterialValue -= PieceValue(captured);
                }
                if (captured == Rook)
                {
                    if (dest == (int)Cell.h1)
                        castlingStatus &= ~CastlingAvail.KingSideWhite;
                    else if (dest == (int)Cell.a1)
                        castlingStatus &= ~CastlingAvail.QueenSideWhite;
                    else if (dest == (int)Cell.a8)
                        castlingStatus &= ~CastlingAvail.QueenSideBlack;
                    else if (dest == (int)Cell.h8)
                        castlingStatus &= ~CastlingAvail.KingSideBlack;
                }
            }
            // new en passant square..
            int ep = enPassantSquare;
            enPassantSquare = 0x88;
            if (  moving == Pawn   )
            {
                halfMoves = 0;
                if (dest == ep )
                {
                    captureEnPassant = true;

                    if (toMove == Side.White)
                    {
                        blackMaterialValue -= PawnValue;
                        capturePromotionStatus = dest-16;
                        capturePromotionStatus |= pieceList[board[dest - 16]] << 8;
                        pieceList[board[dest - 16]] = 0x88;
                        board[dest - 16] = NoPiece;
                    }
                    else
                    {
                        whiteMaterialValue -= PawnValue;
                        capturePromotionStatus = dest + 16;
                        capturePromotionStatus |= pieceList[board[dest + 16]] << 8;
                        pieceList[board[dest + 16]] = 0x88;
                        board[dest + 16] = NoPiece;
                    }
                }
                if (toMove == Side.White)
                {
                    if ((start >> 4) == 1 && (dest >> 4) == 3)
                        enPassantSquare = dest - 16;
                }
                else
                {
                    if ((start >> 4) == 6 && (dest >> 4) == 4)
                        enPassantSquare = dest + 16;
                }
            }else
            // castling...
            if (moving == King)
            {
               
                if (start == (int)Cell.e1 && dest == (int)Cell.g1)
                {
                    pieceList[board[(int)Cell.h1]] = (Rook<<8 | (int)Cell.f1);
                    board[(int)Cell.f1] = board[(int)Cell.h1];
                    board[(int)Cell.h1] = NoPiece;
                }
                if (start == (int)Cell.e1 && dest == (int)Cell.c1)
                {
                    pieceList[board[(int)Cell.a1]] = (Rook << 8 | (int)Cell.d1);
                    board[(int)Cell.d1] = board[(int)Cell.a1];
                    board[(int)Cell.a1] = NoPiece;
                }
                if (start == (int)Cell.e8 && dest == (int)Cell.g8)
                {
                    pieceList[board[(int)Cell.h8]] = (Rook << 8 | (int)Cell.f8);
                    board[(int)Cell.f8] = board[(int)Cell.h8];
                    board[(int)Cell.h8] = NoPiece;
                }
                if (start == (int)Cell.e8 && dest == (int)Cell.c8)
                {
                    pieceList[board[(int)Cell.a8]] = (Rook << 8 | (int)Cell.d8);
                    board[(int)Cell.d8] = board[(int)Cell.a8];
                    board[(int)Cell.a8] = NoPiece;
                }
                if( toMove == Side.White )
                    castlingStatus &= ~(CastlingAvail.KingSideWhite | CastlingAvail.QueenSideWhite);
                else
                    castlingStatus &= ~(CastlingAvail.KingSideBlack | CastlingAvail.QueenSideBlack);
            }else
            // castling status update for rook movements...
            if (moving == Rook)
            {
                if (start == (int)Cell.h1)
                    castlingStatus &= ~CastlingAvail.KingSideWhite;
                if (start == (int)Cell.a1)
                    castlingStatus &= ~CastlingAvail.QueenSideWhite;
                if (start == (int)Cell.h8)
                    castlingStatus &= ~CastlingAvail.KingSideBlack;
                if (start == (int)Cell.a8)
                    castlingStatus &= ~CastlingAvail.QueenSideBlack;
            }
            //if (captured != NoPiece && captureEnPassant == false)
            //    pieceList[eindex] = 0x88;
            if (toMove == Side.Black)
            {
                movesCount++;
                toMove = Side.White;
            }
            else
            {
                toMove = Side.Black;
            }
        }
        
        /// <summary>
        /// This function check if a pseudo legal move is legal
        /// WHITOUT CHECKING FOR KING IN ATTACK!
        /// </summary>
        /// <param name="move">the move to check</param>
        /// <returns></returns>
        public bool IsMoveLegal(int move)
        {
            int start = move & 0xFF;
            int dest = (move >> 8) & 0xFF;
            int moving = (move >> 16) & 0xF;
            Side enemy = toMove == Side.White ? Side.Black:Side.White;
            if (moving == King)
            {
                if (start == (int)Cell.e1 && dest == (int)Cell.g1)
                {
                    if (InAttack((int)Cell.f1, enemy)
                        ||
                        InAttack((int)Cell.g1, enemy)
                        ||
                        InAttack((int)Cell.e1, enemy)
                        )
                        return false;
                }
                else if (start == (int)Cell.e1 && dest == (int)Cell.c1)
                {
                    if (InAttack((int)Cell.d1, enemy)
                        ||
                        InAttack((int)Cell.c1, enemy)
                        ||
                        InAttack((int)Cell.e1, enemy)
                        )
                        return false;
                }
                else
                if (start == (int)Cell.e8 && dest == (int)Cell.g8)
                {
                    if (InAttack((int)Cell.f8, enemy)
                        ||
                        InAttack((int)Cell.g8, enemy)
                        ||
                        InAttack((int)Cell.e8, enemy)
                        )
                        return false;
                }
                else if (start == (int)Cell.e8 && dest == (int)Cell.c8)
                {
                    if (InAttack((int)Cell.d8, enemy)
                        ||
                        InAttack((int)Cell.c8, enemy)
                        ||
                        InAttack((int)Cell.e8, enemy)
                        )
                        return false;
                }

            }
            return true;
            
        }
        private int[] movesForPerft;
        private int perftIndex;
        /// <summary>
        /// This is the classic perft test ( Robert Hyatt and others )
        /// Useful for testing speed and move generator correctness.
        /// 
        /// </summary>
        /// <param name="depth">the depth to reach</param>
        /// <returns>a time elapsed and  moves count</returns>
        public PerfResults Perft(int depth)
        {
            movesForPerft = new int[1000];
            perftIndex = 0;
            Stopwatch sw = new Stopwatch();
            PerfResults perft = new PerfResults();
            sw.Start();
            perft.MovesCount = InternalPerft(depth,perftIndex);
            sw.Stop();
            perft.Elapsed = (ulong)sw.ElapsedMilliseconds;
            return perft;
        }
        private ulong InternalPerft(int depth,int index)
        {
            if (depth == 0)
            {
                return 1;
            }
            ulong count = 0;
            int moveCount = GeneratePseudoLegalMoves(index, movesForPerft);
            
            for (int i = index; i < index + moveCount; ++i)
            {
                if (IsMoveLegal( movesForPerft[i]))
                {
#if CHECK_UNDO 
                    string check = SavePos();
#endif
                    Move(movesForPerft[i]);
                   
#if CHECK_BITMASK && BITMASK
                    ChessBoard bTest = new ChessBoard(SavePos());
                    Debug.Assert(bTest.WhitePieces == WhitePieces);
                    Debug.Assert(bTest.BlackPieces == BlackPieces);
#endif

                    if (InAttack(GetKingSquare(toMove == Side.White ? Side.Black:Side.White),toMove) )
                    {
                        UndoMove(movesForPerft[i]);
#if CHECK_BITMASK && BITMASK
                        bTest = new ChessBoard(SavePos());
                        Debug.Assert(bTest.WhitePieces == WhitePieces);
                        Debug.Assert(bTest.BlackPieces == BlackPieces);
#endif
#if CHECK_UNDO
                        Debug.Assert(SavePos()==check,string.Format("Wrong fen after undo:{0}\nPrevious fen={1}\nMove={2}",SavePos(),check,this.ToLiteralMove(movesForPerft[i])));
#endif
                        continue;
                    }
                    ulong n = InternalPerft(depth - 1, index + moveCount);
                    count += n;
                    UndoMove(movesForPerft[i]);
#if CHECK_BITMASK && BITMASK
                    bTest = new ChessBoard(SavePos());
                    Debug.Assert(bTest.WhitePieces == WhitePieces);
                    Debug.Assert(bTest.BlackPieces == BlackPieces);
#endif
#if CHECK_UNDO
                    Debug.Assert(SavePos() == check, string.Format("Wrong fen after undo:{0}\nPrevious fen={1}\nMove={2}", SavePos(), check, this.ToLiteralMove(movesForPerft[i])));
#endif

                }
            }
            return count;
        }


        /// <summary>
        /// Returns if a square is attacked by a side.
        /// </summary>
        /// <param name="index">The 0x88 index of the square</param>
        /// <param name="fromSide">the side to check if attacking square</param>
        /// <returns>true if the square is attacked by fromSide</returns>
        public bool InAttack(int index,Side fromSide)
        {
            /*
            int[] pawnMoves; 
            int enemy; 
            int movingSide; 
            int[] pieceList; 
            int pawnAttackRank;
            int dest, i;
            if( fromSide == Side.Black )
            {
                pawnMoves = blackPawnMoves;
                enemy = Black;
                movingSide = White;
                pawnAttackRank = (index + 16)&0xF0;
                pieceList = blackPieces;
            }
            else
            {
                enemy = White;
                pawnMoves = whitePawnsMoves;
                movingSide = Black;
                pawnAttackRank = (index - 16)&0xF0;
                pieceList = whitePieces;
            }
            
            for (i = 0; i < pieceList.Length; ++i)
            {
                int opponentSquare = pieceList[i];
                if ((opponentSquare & 0x88) != 0)
                    continue;
                int opponent = board[opponentSquare] & PieceMask;
                if (opponent == Pawn
                    &&
                    (opponentSquare & 0xF0)==pawnAttackRank 
                    )
                {
                    for (int j = 2; j <= 3; ++j)
                    {
                        dest = pawnMoves[j] + opponentSquare;
                        if (dest == index)
                            return true;
                    }
                }
                else if (opponent == King)
                {
                    for (int j = 0; j < 8; ++j)
                    {
                        dest = kingMoves[j] + opponentSquare;
                        if (dest == index)
                            return true;
                    }
                }
                else if (opponent == Knight)
                {
                    for (int j = 0;  j < 8; ++j)
                    {
                        dest = knightMoves[j] + opponentSquare;
                        if (dest == index)
                            return true;
                    }
                }
                
                if ((opponent & IsSliding) == 0)
                    continue;
                if ((opponent & DiagSliding) != 0
                    && diagAttacks[0x77 + opponentSquare - index]
                    )
                {
                    for (int j = 0; j < 4; ++j)
                    {
                        dest = opponentSquare + diagMoves[j];
                        while ((dest & 0x88) == 0 && (board[dest] & enemy) == 0)
                        {
                            if( dest == index )
                                return true;
                            if ((board[dest] & movingSide) != 0)
                                break;
                            dest += diagMoves[j];
                        }
                    }
                }
                if ((opponent & StraightSliding) != 0
                    &&  straightAttacks[0x77 + opponentSquare - index] 
                    )
                {
                    for (int j = 0; j < 4; ++j)
                    {
                        dest = opponentSquare + straightMoves[j];
                        while ((dest & 0x88) == 0 && (board[dest] & enemy) == 0)
                        {
                            if (dest == index)
                            {
                                return true;
                            }
                            if ((board[dest] & movingSide) != 0)
                                break;
                            dest += straightMoves[j];
                        }
                    }
                }
            }
            */
            
            return false;
        }
        /// <summary>
        /// This is the perf test, usefull to benchmark move generation
        /// and move / undo move performances
        /// </summary>
        /// <param name="undoRedo">The results for doing undoing moves...</param>
        /// <param name="nofLoops">The loop count to run the generation </param>
        /// <returns></returns>
        public PerfResults Perf(out PerfResults undoRedo,int nofLoops)
        {
            undoRedo = new PerfResults();
            int[] moves = new int[100];
            PerfResults res = new PerfResults();
            Stopwatch sw = new Stopwatch();
            sw.Start();
            for (int i = 0; i < nofLoops; ++i)
            {
                res.MovesCount += (ulong)GeneratePseudoLegalMoves(0, moves );
            }
            sw.Stop();
            res.Elapsed = (ulong)sw.ElapsedMilliseconds;
            sw.Start();
            for (int i = 0; i < nofLoops; ++i)
            {
                int n = GeneratePseudoLegalMoves(0, moves);
                undoRedo.MovesCount += (ulong)n;
                for (int m = 0; m < n; ++m)
                {
                    Move(moves[m]);
                    UndoMove(moves[m]);
                }
            }
            sw.Stop();
            undoRedo.Elapsed = (ulong)sw.ElapsedMilliseconds;
            return res;
        }
        /// <summary>
        /// returns the square in wich the king is...
        /// </summary>
        /// <param name="s">The color of the king needed</param>
        /// <returns>the ox88 index of the king square</returns>
        public int GetKingSquare(Side s)
        {
            if (s == Side.White)
                return pieceList[0];
            else
                return pieceList[16];
        }
        
        int capturePromotionStatus;
        private void PushStatus()
        {
            ulong status = 0;
            status |= (ulong)(uint)castlingStatus;
            status |= (ulong)(uint)(enPassantSquare << 4);
            status |= (ulong)(uint)(halfMoves << 12);
            status |= (ulong)(uint)(movesCount << 22);
            status |= (ulong)(uint)(capturePromotionStatus << 32);
            statusStack[statusStackPointer++] = status;
        }
        private void PopStatus()
        {
            ulong status = statusStack[--statusStackPointer];
            castlingStatus = (CastlingAvail)(status & 0xF);
            enPassantSquare = (int)(status >> 4) & 0xFF;
            halfMoves = (int)(status >> 12) & 0x3FF ;
            movesCount = (int)(status >> 22) & 0x3FF;
            capturePromotionStatus = (int)(status >> 32);
        }


        private int PieceValue(int piece)
        {
            switch (piece)
            {
                case Pawn:
                    return PawnValue;
                case Knight:
                    return KnightValue;
                case Bishop:
                    return BishopValue;
                case Rook:
                    return RookValue;
                case Queen:
                    return QueenValue;
                case King:
                    return KingValue;
                default:
                    return 0;
            }
        }
       
        /// <summary>
        /// Create a bitboard for a given position
        /// </summary>
        /// <param name="fen">Forsyth-Edwards Notation (FEN) string describing the position</param>
        public ChessBoard(string fen)
        {
            SetBoard(fen);
            statusStackPointer = 0;
        }

        private void ClearBoard()
        {
            for (int i = 0; i < 128; ++i)
                board[i] = NoPiece;
        }

        private void InitPieceList()
        {
            for (int i = 0; i < 32; ++i)
            {
                pieceList[i] = 0x88;
            }
        }
        /// <summary>
        /// return the side that has the move
        /// </summary>
        Side ToMove
        {
            get { return toMove; }
        }

        public int WhiteMaterialValue
        {
            get { return whiteMaterialValue; }
        }
        public int BlackMaterialValue
        {
            get { return blackMaterialValue; }
        }
        /// <summary>
        /// Force a different side to have the move. Just for special commands.
        /// Should not be used...
        /// </summary>
        /// <param name="newSide"></param>
        public void ForceSide(Side newSide)
        {
            toMove = newSide;
        }

        Stack<int> movesStack = new Stack<int>();

        /// <summary>
        /// Do a move in the form "e2e4(qrnb)". This function check for move availability
        /// and avoid leaving king in attack.
        /// So it is suitable for user input.
        /// This function will trow an exception if the move is not acceptable or the
        /// move string cannot be parsed.
        /// </summary>
        /// <param name="p"></param>
        public void Move(string p)
        {
            int[] avail = new int[200];
            int n = GeneratePseudoLegalMoves( 0, avail);
            Regex r = new Regex("(?'s'[abcdefgh][12345678])(?'e'[abcdefgh][12345678])(?'p'[qrbn]?)");
            Match m = r.Match(p);
            if (m.Success == false)
                throw new ChessEngineRecoverableException("Unrecognized move:" + p);
            Cell start = FromLiteralCell(m.Groups["s"].Value);
            Cell end = FromLiteralCell(m.Groups["e"].Value);
            string promotion = string.Empty;
            if (m.Groups["p"] != null)
            {
                promotion = m.Groups["p"].Value;
            }
            int found = 0;
            int template = (int)start | (int)end << 8;
            foreach (int move in avail)
            {
                if ((move & 0xFFFF) == template)
                {
                    if (promotion == string.Empty)
                    {
                        found = move;
                        break;
                    }
                    else
                    {
                        int piece = Queen;
                        switch (promotion)
                        {
                            case "q":
                                piece = Queen;
                                break;
                            case "r":
                                piece = Rook;
                                break;
                            case "b":
                                piece = Bishop;
                                break;
                            case "n":
                                piece = Knight;
                                break;
                        }
                        if ((move >> 24 & 0xF) == piece)
                        {
                            found = move;
                            break;
                        }
                    }
                }
            }
            if (found == 0)
            {
                throw new ChessEngineRecoverableException("Move not available:" + p);
            }
            if (IsMoveLegal(found))
            {
                Move(found);
                if (InAttack(GetKingSquare(toMove == Side.White ? Side.Black : Side.White), toMove))
                {
                    UndoMove(found);
                    throw new ChessEngineRecoverableException("Invalid move,king is in check!:" + p);
                }
                movesStack.Push(found);
            }
            else
                throw new Exception("Move not available:" + p);



        }


        private string GetPieceString(int p) 
        {
            string pp="";
            bool white = 0 != (p & White);
            p &= PieceMask;
            if (p == Pawn)
            {
                pp = "p";
            }
            if (p == Knight)
            {
                pp = "n";
            }
            if (p == Bishop)
            {
                pp = "b";
            }
            if ( p == Rook )
            {
                pp = "r";
            }
            if (p == Queen)
            {
                pp = "q";
            }
            if (p == King)
            {
                pp = "k";
            }
            if (white)
            {
                pp = pp.ToUpper();
            }
            return pp;
        }
        
        #region piece values
        public const int PawnValue = 100;
        public const int KnightValue = 300;
        public const int BishopValue = 300;
        public const int RookValue = 500;
        public const int QueenValue = 900;
        public const int KingValue = 1000000;
        #endregion
        /// <summary>
        /// Get the Fn string for the board. The reason the fuunction is not named as GetFen()
        /// Is just because "savepos" is the normal command is associated to this function in 
        /// chess programming.
        /// </summary>
        /// <returns>The Forsyth-Edwards Notation (FEN) string describing the position</returns>
        public string SavePos()
        {
            StringBuilder sb = new StringBuilder();
            SaveParts(sb);
            sb.Append(" ");
            SaveToMove(sb);
            sb.Append(" ");
            SaveCastling(sb);
            sb.Append(" ");
            SaveEnPassant(sb);
            sb.Append(" ");
            sb.Append(halfMoves.ToString());
            sb.Append(" ");
            sb.Append(movesCount.ToString());
            return sb.ToString();
        }
        #region Fen Saving...
        private void SaveEnPassant(StringBuilder sb)
        {
            sb.Append(FromCellToLiteral((Cell)enPassantSquare));
        }

        private void SaveCastling(StringBuilder sb)
        {
            if (castlingStatus == CastlingAvail.None)
                sb.Append("-");
            else
            {
                if (0 != (castlingStatus & CastlingAvail.KingSideWhite))
                {
                    sb.Append("K");
                }
                if (0 != (castlingStatus & CastlingAvail.QueenSideWhite))
                {
                    sb.Append("Q");
                }
                if (0 != (castlingStatus & CastlingAvail.KingSideBlack))
                {
                    sb.Append("k");
                }
                if (0 != (castlingStatus & CastlingAvail.QueenSideBlack))
                {
                    sb.Append("q");
                }
            }
        }

        private void SaveToMove(StringBuilder sb)
        {
            if (toMove == Side.White)
                sb.Append("w");
            else
                sb.Append("b");
        }

        private void SaveParts(StringBuilder sb)
        {
            int emptyCount = 0;
            for (int i = 112; i >= 0; i-=16)
            {
                for (int ii = i; ii < i + 9; ++ii)
                {
                    if (0 != (ii & 0x88))
                    {
                        if (emptyCount > 0)
                            sb.Append(emptyCount);
                        if (i > 0)
                            sb.Append("/");
                        emptyCount = 0;
                        break;
                    }
                    if (board[ii] == NoPiece)
                    {
                        emptyCount++;
                    }
                    else
                    {
                        if (emptyCount > 0)
                        {
                            sb.Append(emptyCount);
                            emptyCount = 0;
                        }
                        sb.Append(GetPieceString(board[ii]));
                    }
                }
            }
        }
        #endregion
       
        /// <summary>
        /// Set the board at a specified fen
        /// </summary>
        /// <param name="fen">Forsyth-Edwards Notation (FEN) string describing the position</param>
        public void SetBoard(string fen)
        {
            if (fen == null)
                throw new ArgumentNullException("fen");
            InitPieceList();
            ClearBoard();
           
            movesStack = new Stack<int>();
            string[] fenParts = fen.Trim().Split(' ');
            for (int i = 0; i < board.Length; ++i)
            {
                board[i] = NoPiece;
            }
            whiteMaterialValue = 0;
            blackMaterialValue = 0;
            halfMoves = 0;
            movesCount = 0;
            castlingStatus = CastlingAvail.None;
            enPassantSquare = (int)Cell.Invalid;
            if (fenParts.Length != 6)
                throw new Exception("Invalid fen:" + fen);
            ParseParts(fenParts[0]);
            ParseToMove(fenParts[1]);
            ParseCastling(fenParts[2]);
            ParseEnPassant(fenParts[3]);
            if (false == int.TryParse(fenParts[4], out halfMoves))
                throw new Exception("Half moves count cannot be parsed:" + fenParts[4]);
            if (false == int.TryParse(fenParts[5], out movesCount))
                throw new Exception("Moves count cannot be parsed:" + fenParts[5]);
            if (movesCount < 1)
                throw new Exception("Moves count less than 1:" + fenParts[5]);
        }
        #region fen parsing privates
        private void ParseEnPassant(string p)
        {
            if (p == "-")
                return;
            FieldInfo fi = typeof(Cell).GetField(p);
            if (fi == null)
                throw new Exception("Invalid Fen cell en passant specification:" + p);
            enPassantSquare = (int)fi.GetRawConstantValue();
        }

        private void ParseCastling(string p)
        {
            foreach (char c in p)
            {
                switch (c)
                {
                    case 'k':
                        castlingStatus |= CastlingAvail.KingSideBlack;
                        break;
                    case 'K':
                        castlingStatus |= CastlingAvail.KingSideWhite;
                        break;
                    case 'q':
                        castlingStatus |= CastlingAvail.QueenSideBlack;
                        break;
                    case 'Q':
                        castlingStatus |= CastlingAvail.QueenSideWhite;
                        break;
                }
            }
        }

        private void ParseToMove(string p)
        {
            if (p == "w")
                toMove = Side.White;
            else
                toMove = Side.Black;
        }
        /// <summary>
        /// Helper stuct to collect piece in lists parsing the fen.
        /// Collecting lists make easier build the subsequential pice list array
        /// </summary>
        struct FenPiece:IComparable
        {
            public int cell;
            public int piece;

            #region IComparable Members

            public int CompareTo(object obj)
            {
                FenPiece other = (FenPiece)obj;
                return GetComparableValue() - other.GetComparableValue();
            }

            #endregion
            private int GetComparableValue()
            {
                switch (piece)
                {
                    case Pawn:
                        return 1;
                    case King:
                        return 0;
                    case Knight:
                        return 2;
                    case Bishop:
                        return 4;
                    case Rook:
                        return 5;
                    case Queen:
                        return 3;
                    default:
                        throw new Exception("Internal error:Unknown piece code");
                }
            }
        }
        private void ParseParts(string parts)
        {
            List<FenPiece> whites = new List<FenPiece>();
            List<FenPiece> blacks = new List<FenPiece>();
            int rank = 7;
            int file = 1;
            FenPiece piece;
            foreach (char c in parts)
            {
                if (char.IsLetter(c))
                {
                    int side  = char.IsLower(c)? Black:White;
                    int partValue = 0;    
                    char p = char.ToLower(c);
                    int f = file - 1;
                    List<FenPiece> current;
                    if (side == Black)
                        current = blacks;
                    else
                        current = whites;
                    switch (p)
                    {
                        case 'p':
                            piece = new FenPiece();
                            piece.piece = Pawn;
                            piece.cell = rank * 16 + f;
                            current.Add(piece);
                            partValue += PawnValue;
                            break;
                        case 'n':
                            piece = new FenPiece();
                            piece.piece = Knight;
                            piece.cell = rank * 16 + f;
                            current.Add(piece);
                            partValue += KnightValue;
                            break;
                        case 'b':
                            piece = new FenPiece();
                            piece.piece = Bishop;
                            piece.cell = rank * 16 + f;
                            current.Add(piece);
                            partValue += BishopValue;
                            break;
                        case 'r':
                            piece = new FenPiece();
                            piece.piece = Rook;
                            piece.cell = rank * 16 + f;
                            current.Add(piece);
                            partValue += RookValue;
                            break;
                        case 'q':
                            piece = new FenPiece();
                            piece.piece = Queen;
                            piece.cell = rank * 16 + f;
                            current.Add(piece);
                            partValue += RookValue;
                            partValue += QueenValue;
                            break;
                        case 'k':
                            piece = new FenPiece();
                            piece.piece = King;
                            piece.cell = rank * 16 + f;
                            current.Add(piece);
                            partValue += RookValue;
                            partValue += KingValue;
                            break;
                    }
                    if (side == Black)
                    {
                        blackMaterialValue += partValue;
                    }
                    else
                    {
                        whiteMaterialValue += partValue;
                    }
                    file++;
                }
                if (char.IsDigit(c))
                    file += int.Parse(new string(c,1));
                else
                    if (c == '/')
                    {
                        file = 1;
                        rank--;
                    }
            }
            whites.Sort();
            blacks.Sort();
            firstSliderWhite=CreatePieceList(0,whites,out lastSliderWhite);
            firstSliderBlack = CreatePieceList(16, blacks,out lastSliderBlack);
        }

        private int CreatePieceList(int p, List<FenPiece> pieces,out int lastSlider)
        {
            int i = p;
            int pawnEnd = i+9;
            int firstSlider = 33;
            lastSlider = 0;
            foreach (FenPiece fp in pieces)
            {
                if (fp.piece != Pawn && fp.piece != King && i<pawnEnd )
                    i = pawnEnd;
                pieceList[i] = (short)fp.cell;
                pieceList[i] |= (short)(fp.piece << 8);
                board[fp.cell] = i;
                if (0 != (fp.piece & IsSliding) && firstSlider == 33)
                {
                    firstSlider = i;
                }
                i++;
            }
            if (firstSlider != 33)
                lastSlider = i - 1;

            return firstSlider;
        }
#endregion
        /// <summary>
        /// Get the castling availability status
        /// </summary>
        public CastlingAvail CastlingStatus
        {
            get { return castlingStatus; }
        }
        /// <summary>
        /// Get the en passant cell for the board. Could be invalid value
        /// casting to int returns a cell index based 0n 0x88 little endian board representation
        /// </summary>
        public Cell EnPassantIndex
        {
            get { return (Cell)enPassantSquare; }
        }
        /// <summary>
        /// Convert a cell in 0x88 representation in an index 0..63 where a1 is 0 and h8 is 63
        /// </summary>
        /// <param name="cell">The ox88 cell index</param>
        /// <returns>the 8x8 cell index ( -1 if invalid cell )</returns>
        public static int FromCellTo8x8( Cell cell)
        {
            if (0 != (cell & Cell.Invalid))
                return -1;
            else
            {
                int idx = (int)cell;
                return (idx >> 4) * 8 + (idx & 0xF);
            }
        }
        /// <summary>
        /// return a cell in the format a1,c3,h8 etc in the 0x88 index
        /// </summary>
        /// <param name="cell">the cell string</param>
        /// <returns>the 0x88 cell</returns>
        public static Cell FromLiteralCell(string cell)
        {
            if (!Regex.IsMatch(cell, "[a-h][1-8]"))
                throw new Exception("Invalid cell specification:" + cell);
            string files = "abcdefgh";
            int file = files.IndexOf(cell.Substring(0, 1));
            int rank = int.Parse(cell.Substring(1, 1))-1;
            return (Cell)(rank * 16 + file);
        }
        /// <summary>
        /// returns a cell in the format a1,c3,h8 etc in the 0x88 index from Cell enum in 0x88 format
        /// </summary>
        /// <param name="cell"></param>
        /// <returns></returns>
        public static string FromCellToLiteral(Cell cell)
        {
            if (cell == Cell.Invalid)
                return "-";
            string files = "abcdefgh";
            int idx8x8 = FromCellTo8x8(cell);
            if (idx8x8 == -1)
                return "-";
            return files.Substring(idx8x8 % 8, 1) + ((idx8x8 / 8)+1).ToString();
        }

        /// <summary>
        /// Get the moves count. The count is incremented at each black move and starts from 1.
        /// </summary>
        public int MovesCount
        {
            get { return movesCount; }
        }
        /// <summary>
        /// Gets the number of halfmoves since the last pawn advance or capture.
        /// </summary>
        public int HalfMovesCount
        {
            get { return halfMoves; }
        }
        int whiteMaterialValue;
        int blackMaterialValue;
        int halfMoves; // 50 moves drawing rule...
        int movesCount;
        int[] board = new int[128];
        ulong[] statusStack = new ulong[1000];
        Side toMove;
        int enPassantSquare; // invalid square
        CastlingAvail castlingStatus;


        /// <summary>
        /// This function is an user callable UndoMove, that rollback a move
        /// done by Move( string )
        /// </summary>
        public void UndoMove()
        {
            if (movesStack.Count == 0)
                throw new ChessEngineRecoverableException("Moves stack underflow:nothing to undo");
            else
                UndoMove(movesStack.Pop());
        }
        /// The piece containined in a square
        /// To describe the part only 4 bit is necessary ( this is significant only for move packing )
        /// The part color is maskable with the part.
        public const int PieceMask = 0xF;
        public const int NoPiece = -1;
        public const int Pawn = 0x1;
        public const int Knight = 2;
        public const int King = 3;
        public const int Rook = 4;
        public const int Bishop = 8;
        public const int Queen = 12;
        public const int IsSliding = 12;
        public const int DiagSliding = 8;
        public const int StraightSliding = 4;
        public const int White = 16;
        public const int Black = 32;




        /// <summary>
        /// Dump a board in a form suitable for a console application.
        /// </summary>
        /// <param name="tw">The text writer to dump the board</param>
        public void Dump(TextWriter tw)
        {
            string row = " +---+---+---+---+---+---+---+---+";
            for (int i = 8; i > 0; --i)
            {
                tw.WriteLine(row);
                tw.WriteLine(i.ToString() + LiteralPartInRank(i-1));
            }
            tw.WriteLine(row);
            tw.WriteLine("   a   b   c   d   e   f   g   h");
        }
        private string LiteralPartInRank(int nRank)
        {
            StringBuilder sb = new StringBuilder();
            for (int file = 0; file < 8; ++file)
            {
                sb.Append('|');
                string part = " · ";
                switch (board[nRank * 16 + file] & PieceMask)
                {
                    case Pawn:
                        part = " P ";
                        break;
                    case Bishop:
                        part = " B ";
                        break;
                    case Knight:
                        part = " N ";
                        break;
                    case Rook:
                        part = " R ";
                        break;
                    case Queen:
                        part = " Q ";
                        break;
                    case King:
                        part = " K ";
                        break;
                }
                if ((board[nRank * 16 + file] & Black) != 0)
                    part = part.ToLower();
                sb.Append(part);
            }
            sb.Append("|");
            return sb.ToString();
        }
        // Piece List:
        // 0-16 = White pieces 16-32 = black pieces 
        // offsets: 0 = King 1-8 = Pawns then leapers and sliders ( offset is indexed by firstSliderBlack / firstSliderWhite
        int firstSliderBlack;
        int firstSliderWhite;
        int lastSliderWhite;
        int lastSliderBlack;
        
        short[] pieceList = new short[32];
    }
}
